package org.summerb.microservices.articles.mvc;
import java.util.Collections;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.summerb.approaches.jdbccrud.api.dto.PaginatedList;
import org.summerb.approaches.jdbccrud.api.query.Query;
import org.summerb.approaches.jdbccrud.mvc.EasyCrudControllerBase;
import org.summerb.approaches.jdbccrud.mvc.filter.FilteringParamsToQueryConverter;
import org.summerb.approaches.jdbccrud.mvc.filter.FilteringParamsToQueryConverterImpl;
import org.summerb.approaches.jdbccrud.mvc.model.EasyCrudQueryParams;
import org.summerb.approaches.security.api.exceptions.NotAuthorizedException;
import org.summerb.approaches.springmvc.controllers.ControllerBase;
import org.summerb.approaches.springmvc.model.MessageSeverity;
import org.summerb.approaches.springmvc.model.PageMessage;
import org.summerb.approaches.springmvc.utils.ErrorUtils;
import org.summerb.approaches.springmvc.utils.MimeTypeResolver;
import org.summerb.microservices.articles.api.ArticleRenderer;
import org.summerb.microservices.articles.api.ArticleService;
import org.summerb.microservices.articles.api.AttachmentService;
import org.summerb.microservices.articles.api.dto.Attachment;
import org.summerb.microservices.articles.api.dto.consuming.RenderedArticle;
@Controller
public class ArticleController extends ControllerBase {
public static final long HOUR = 1000L * 60L * 60L;
public static final long DAY = HOUR * 24L;
private Logger log = Logger.getLogger(getClass());
private static final String ATTR_ARTICLE = "article";
@Autowired
private ArticleRenderer articleRenderer;
@Autowired
private ArticleService articleService;
@Autowired
private AttachmentService attachmentService;
@Autowired
private MimeTypeResolver mimeTypeResolver;
private String viewNameArticle = "articles/article";
private FilteringParamsToQueryConverter filteringParamsToQueryConverter = new FilteringParamsToQueryConverterImpl();
@SuppressWarnings("serial")
public static class AttachmentNotFoundException extends Exception {
public AttachmentNotFoundException(long id) {
super("article attachment " + id + " not found");
}
}
@RequestMapping(method = RequestMethod.GET, value = "/articles-attachments/{id}/{proposedName}")
public ResponseEntity<InputStreamResource> getAttachment(Model model, @PathVariable("id") long id,
HttpServletResponse response) throws AttachmentNotFoundException {
try {
Attachment attachment = attachmentService.findById(id);
if (attachment == null) {
throw new AttachmentNotFoundException(id);
}
long now = new Date().getTime();
HttpHeaders headers = new HttpHeaders();
headers.setCacheControl("private");
headers.setExpires(now + DAY);
headers.setContentType(
MediaType.parseMediaType(mimeTypeResolver.resolveContentTypeByFileName(attachment.getName())));
headers.setContentLength((int) attachment.getSize());
response.setHeader("Content-Disposition", "attachment; filename=\"" + attachment.getName() + "\"");
// NOTE: Looks like there is a bug in the spring - it will add
// Last-Modified twice to the response
// responseHeaders.setLastModified(maxLastModified);
response.setDateHeader("Last-Modified", now);
InputStreamResource ret = new InputStreamResource(articleService.getAttachmnetContent(id));
return new ResponseEntity<InputStreamResource>(ret, headers, HttpStatus.OK);
} catch (AttachmentNotFoundException t) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
response.setHeader("Error", "File not found");
return null;
} catch (Throwable t) {
log.warn("Failed to get article attachment", t);
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.setHeader("Error", "Failed to get article attachment -> " + ErrorUtils.getAllMessages(t));
return null;
}
}
@RequestMapping(method = RequestMethod.GET, value = "/articles-attachments/{id}")
public ModelAndView getAttachment2(Model model, @PathVariable("id") long id, HttpServletResponse response) {
try {
Attachment attachment = attachmentService.findById(id);
response.setContentType(mimeTypeResolver.resolveContentTypeByFileName(attachment.getName()));
response.setContentLength((int) attachment.getSize());
response.setHeader("Content-Disposition", "attachment; filename=\"" + attachment.getName() + "\"");
FileCopyUtils.copy(articleService.getAttachmnetContent(id), response.getOutputStream());
return null;
} catch (Throwable t) {
log.debug("Failed to get article attachment", t);
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.setHeader("Error", "Failed to get article attachment -> " + ErrorUtils.getAllMessages(t));
return null;
}
}
@RequestMapping(method = RequestMethod.GET, value = "/articles/{articleKey}")
public String get(Model model, @PathVariable("articleKey") String articleKey, HttpServletResponse respons,
Locale locale) {
try {
RenderedArticle article = articleRenderer.renderArticle(articleKey, locale);
model.addAttribute(ATTR_ARTICLE, article);
} catch (Throwable t) {
log.debug("Failed to get article", t);
addPageMessage(model.asMap(), new PageMessage(ErrorUtils.getAllMessages(t), MessageSeverity.Danger));
}
return viewNameArticle;
}
@RequestMapping(method = RequestMethod.POST, value = "/rest/articles-attachments/ajaxList")
public @ResponseBody Map<String, ? extends Object> ajaxList(@RequestBody EasyCrudQueryParams filteringParams,
HttpServletResponse response) throws NotAuthorizedException {
Query query = filteringParamsToQueryConverter.convert(filteringParams.getFilterParams(),
attachmentService.getDtoClass());
PaginatedList<Attachment> ret = attachmentService.query(filteringParams.getPagerParams(), query,
filteringParams.getOrderBy());
return Collections.singletonMap(EasyCrudControllerBase.ATTR_LIST, ret);
}
public String getViewNameArticle() {
return viewNameArticle;
}
public void setViewNameArticle(String viewNameArticle) {
this.viewNameArticle = viewNameArticle;
}
}